package com.hmall.search.service.impl;

import cn.hutool.core.util.ObjectUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.FunctionBoostMode;
import co.elastic.clients.elasticsearch._types.query_dsl.FunctionScoreMode;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.json.JsonData;
import com.hmall.common.domain.PageDTO;
import com.hmall.search.domain.po.ItemDoc;
import com.hmall.search.domain.query.ItemPageQuery;
import com.hmall.search.service.ISearchService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;


@Service
@Slf4j
@AllArgsConstructor
public class SearchServiceImpl implements ISearchService {

    private final ElasticsearchClient esClient;

    @Override
    public PageDTO<ItemDoc> search(ItemPageQuery query) throws IOException {
        SearchResponse<ItemDoc> response = esClient.search(builder -> builder.index("items")
                        .query(queryBuilder -> queryBuilder
                                .functionScore(functionScoreBuilder -> functionScoreBuilder
                                        .query(qbBuilder -> qbBuilder.bool(boolBuilder -> {
                                            if (ObjectUtil.isNotEmpty(query.getKey())) {
                                                boolBuilder.must(mustBuilder -> mustBuilder.match(mBuilder -> mBuilder
                                                        .field("name").query(query.getKey())));
                                            }
                                            if (ObjectUtil.isNotEmpty(query.getCategory())) {
                                                boolBuilder.filter(filterBuilder -> filterBuilder.term(termBuilder -> termBuilder
                                                        .field("category").value(query.getCategory())));
                                            }
                                            if (ObjectUtil.isNotEmpty(query.getBrand())) {
                                                boolBuilder.filter(filterBuilder -> filterBuilder.term(termBuilder -> termBuilder
                                                        .field("brand").value(query.getBrand())));
                                            }
                                            if (ObjectUtil.isNotNull(query.getMinPrice())) {
                                                boolBuilder.filter(filterBuilder -> filterBuilder.range(rangeBuilder -> rangeBuilder
                                                        .field("price").gte(JsonData.of(query.getMinPrice()))));
                                            }
                                            if (ObjectUtil.isNotNull(query.getMaxPrice())) {
                                                boolBuilder.filter(filterBuilder -> filterBuilder.range(rangeBuilder -> rangeBuilder
                                                        .field("price").lte(JsonData.of(query.getMaxPrice()))));
                                            }
                                            return boolBuilder;
                                        }))
                                        .functions(functionBuilder -> functionBuilder
                                                .filter(filterBuilder -> filterBuilder.term(termBuilder -> termBuilder
                                                                .field("isAD")
                                                                .value(true)))
                                                .weight(100d))
                                        .boostMode(FunctionBoostMode.Multiply)))
                        .sort(sortOptionBuilder -> sortOptionBuilder
                                .field(fieldBuilder -> {
                                    //如果没有排序条件，就用默认的排序条件，否则用已有的
                                    if (ObjectUtil.isEmpty(query.getSortBy())) {
                                        return fieldBuilder.field("_score");
                                    } else {
                                        return fieldBuilder
                                                .field(query.getSortBy())
                                                .order(query.getIsAsc() ? SortOrder.Asc : SortOrder.Desc);
                                    }
                                }))
                        .from((query.getPageNo() - 1) * query.getPageSize())
                        .size(query.getPageSize())
                        .highlight(highlightBuilder -> highlightBuilder
                                .fields("name", fieldsBuilder -> fieldsBuilder
                                        .preTags("<em style='color:red'>")
                                        .postTags("</em>")))
                , ItemDoc.class);
        long total = response.hits().total().value();
        List<ItemDoc> list = new ArrayList<>();
        for (Hit<ItemDoc> hit : response.hits().hits()) {
            ItemDoc itemDoc = hit.source();
            List<String> nameHighlight = hit.highlight().get("name");
            if(ObjectUtil.isNotEmpty(nameHighlight)){
                itemDoc.setName(nameHighlight.get(0));
            }
            list.add(itemDoc);
        }

        PageDTO<ItemDoc> pageDTO = new PageDTO<>();
        pageDTO.setTotal(total);
        pageDTO.setList(list);

        return pageDTO;
    }
}
